import csv
import json
import urllib.parse
import urllib.request
from pyecharts import options as opts
from pyecharts.globals import GeoType
from pyecharts.charts import Geo

# 1)csv文件获取省份所包含的地州市名称
# {'湖南省':['长沙市', '湘潭市', ……]}
admin_district = {}
dist_file_path = 'human_stats/data/administrative_district.csv'
with open(file=dist_file_path, mode='r', encoding='gbk') as district_file:
    district_reader = csv.DictReader(district_file)

    for district in district_reader:
        # 取province_name,city_name两列数据
        province = district['province_name']
        city = district['city_name']

        # cities=[],包含地州市名称的列表
        cities = admin_district.get(province, [])
        # 判断城市名称是否已经在列表中
        if city in cities:
            continue
        else:
            cities.append(city)

        admin_district[province] = cities


# 2)API查询湖南省14个地州市的经纬度并写入JSON文件
# 格式：{"长沙": [113, 28.21]}
city_point = {}
for city_name in admin_district['湖南省']:
    api_url = 'http://api.tianditu.gov.cn/v2/administrative?' + \
              'keyword=' + urllib.parse.quote(city_name) + \
              '&childLevel=0&tk=替换成你自己申请的key'
    # Bytes -> JSON -> dict
    req = urllib.request.Request(url=api_url)
    
    try:
        # urlopen返回的是字节对象
        resp = urllib.request.urlopen(req, timeout=5)
    except Exception as e:
        print("访问网络异常", e)
    else:
        # 把bytes转码为utf-8 str
        resp_text = resp.read().decode('utf-8')

    # json -> dict
    resp_json = json.loads(resp_text)

    # 返回值字典“data”的value也是一个字典
    # 字典元素['data']['district'][0]['center']包含有我们需要的数据
    city_data = resp_json['data']['district'][0]['center']

    # 经纬度的值为一个列表，[经度/lng, 纬度/lat]
    city_point[city_name] = [city_data['lng'], city_data['lat']]


# 将经纬度数据写入json文件
coords_json_path = 'human_stats/data/city_coordinate.json'
with open(coords_json_path, mode='w', encoding='utf-8', newline='') as coords_file:
    # ensure_ascii传入字符是否转义
    json.dump(city_point, coords_file, ensure_ascii=False, indent=4)


# 3)获取湖南省14个地州市的人口数
# {'长沙市': 10047914}
city_population = {}
popu_file_path = 'human_stats/data/hunan_population.csv'
with open(file=popu_file_path, mode='r', encoding='gbk') as population_file:
    popu_reader = csv.DictReader(population_file)

    for city_popu in popu_reader:
        # 删除城市名称字符前后的空格
        city_name = city_popu['city'].strip()
        # 丢弃空白数据行
        if len(city_name) == 0:
            continue

        # 城市人口，转成int类型
        population = int(city_popu['population'])

        # 各地州市人口数字典，城市名称为key
        city_population[city_name] = population

# 规范城市名称，与坐标JSON文件保持一致
# pop(key)删除指定key的元素，并返回其value
population = city_population.pop('湘西州')
city_population['湘西土家族苗族自治州'] = population

# 或者使用dict.update()方法
# city_population.update({
#     '湘西土家族苗族自治州': city_population.pop('湘西州')
# })


# 4)创建城市人口的散点图
# 城市人口数的最大和最小值
low, high = min(city_population.values()), max(city_population.values())

# 数据序列，嵌套列表
# [['长沙市', 10047914], ['湘潭市', 2726181]……]
data_serial = [
    list(z) for z in zip(
        city_population.keys(),
        city_population.values()
    )
]

# 创建一个geo对象
geo = (
    Geo(init_opts=opts.InitOpts(js_host='../static_resource/'))
    # 湖南省地图
    .add_schema(maptype="湖南")
    # 使用自定义的城市地图坐标
    .add_coordinate_json(json_file=coords_json_path)
    .add(
        series_name="湖南人口",
        # [[城市名，人口], ……]
        data_pair=data_serial,
        # 带涟漪效果的散点图
        type_=GeoType.EFFECT_SCATTER
    )
    # {b}区域/城市名称
    .set_series_opts(
        label_opts=opts.LabelOpts(is_show=True, formatter='{b}')
    )
    .set_global_opts(
        # 图表的标题和副标题
        title_opts=opts.TitleOpts(
            title="湖南省人口分布",
            subtitle='数据来源：湖南省人口普查年鉴(2020)'
        ),
        # 颜色与点之间视觉映射
        visualmap_opts=opts.VisualMapOpts(min_=low, max_=high)
    )
    # 渲染为html文件
    .render("human_stats/output/hunan_population_geo.html")
)
